﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using parkMonitor.LOG;
using parkMonitor.entity;
using parkMonitor.model;
using System.Configuration;
using System.Threading;
using parkMonitor.server.uiLogServer;
using parkMonitor.tools;
using parkMonitor.DataBase;

namespace parkMonitor.server.CoreThread
{
    /// <summary>
    /// 核心对命令处理父类
    /// </summary>
    public abstract class AbstractCmd
    {
        public static bool isClosing { get; set; }
        //addresses
        public int equipmentStatus_address { set; get; }
        public int park_completed_address { set; get; }
        public int parkingEntX { set; get; }
        public int parkingEntY { set; get; }
        public int parkingEntZ { set; get; }

        public int fetch_completed_address { set; get; }
        public int wheelbase_status_address { get; set; }
        public int parking_startRobot_address { get; set; }
        public int fetching_startRobot_address { get; set; }

        public int frontWheelbase_address { get; set; }
        public int rearWheelbase_address { get; set; }

        //instances
        //public DBLocationOperator locationOper { get; set; }
        public IEquipments PLC { set; get; }
        public IEquipments queuingThread { set; get; }
        public DBOperation oper { set; get; }
        public IEquipments NumMachine { set; get; }
        public CEntrance cEntrance { set; get; }
        public AllotParkingSpace aps { set; get; }

        public AbstractCmd()
        {
            parking_startRobot_address = AddressesForCore.ins.parking_startRobot_address;
            fetching_startRobot_address = AddressesForCore.ins.fetching_startRobot_address;
            equipmentStatus_address = AddressesForCore.ins.equipmentStatus_address;
            park_completed_address = AddressesForCore.ins.park_completed_address;
            parkingEntX = AddressesForCore.ins.parkingEntX;
            parkingEntY = AddressesForCore.ins.parkingEntY;
            parkingEntZ = AddressesForCore.ins.parkingEntZ;
            //轮距
            frontWheelbase_address = AddressesForCore.ins.frontWheelbase_address;
            rearWheelbase_address = AddressesForCore.ins.rearWheelbase_address;
            wheelbase_status_address = AddressesForCore.ins.wheelbase_status_address;
            //取车完成
            fetch_completed_address = AddressesForCore.ins.fetch_completed_address;
            //获取PLC句柄
            PLC = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.PLC);
            //获取队列句柄
            queuingThread = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.Queue);
            //获取号牌机线程句柄
            NumMachine = EquipmentSimpleFactory.ins.FindEquipment(EquipmentName.NumMachine);
            //数据库
            oper = new DBOperation();
            //车位分配
            cEntrance = new CEntrance();
            aps = new AllotParkingSpace();
            Robot.robot1.parking_start_addr = parking_startRobot_address;
            Robot.robot1.fetching_start_addr = fetching_startRobot_address;
            //locationOper = new DBLocationOperator();
        }
        public abstract void executeCmd(Command queueCmd);
        public bool WaitForRobotResource(int robotID)
        {
            PLCMessage PLCMsg = null;
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            lock (Robot.robot1)
            {
                while (!isClosing)
                {
                    PLCMsg = (PLCMessage)PLC.GetMessage();
                    bool occupied = true;
                    if (PLCMsg != null)
                    {
                        if (robotID == 1)
                        {
                            try
                            {
                                Robot.robot1.parking_start_value = Convert.ToInt32(PLCMsg.originalPlcList[parking_startRobot_address].Value);
                                Robot.robot1.fetching_start_value = Convert.ToInt32(PLCMsg.originalPlcList[fetching_startRobot_address].Value);
                                //刷新机械手资源状态值
                                if (Robot.robot1.parking_start_value == 0 && Robot.robot1.fetching_start_value == 0 && !Robot.robot1.occupied)
                                {
                                    occupied = false;
                                }
                                else
                                {
                                    occupied = true;
                                }
                            }
                            catch { }
                        }
                    }
                    if (occupied)
                    {
                        Thread.Sleep(3000);
                    }
                    else
                    {
                        Robot.robot1.occupied = true;
                        UILogServer.ins.log("获得机械手资源");
                        break;
                    }
                    mt.EndTiming();
                    int activationCount = 0;
                    if (mt.IsLonger(60, 1, false, out activationCount))
                    {
                        if (activationCount == 1)
                        {
                            UILogServer.ins.info("无空闲机械手资源，继续等待");
                        }
                        if (MyTimer.restart && !mt.rolledBack)
                        {
                            mt.rolledBack = true;
                            UILogServer.ins.info("启动机械手资源超时，启动回滚");
                            return false;
                        }
                    }
                }
            }
            return true;
        }

        /// /// <summary>
        /// 流程回滚函数
        /// </summary>
        /// <param name="queueCmd"></param>
        /// <param name="parkingSpaceID"></param>
        /// <param name="parkingSpaceUpdated"></param>
        /// <param name="isParking"></param>
        public void Rollback(Command queueCmd, int parkingSpaceID, bool parkingSpaceUpdated, bool isParking)
        {
            string connectionStr = null;
            //命令回退
            queueCmd.returnedCount += 1;
            queuingThread.SetMessage(queueCmd);
            Robot.robot1.occupied = false;
            //复位车辆状态；若已更新过车位则还需复位总车位数，车位状态
            if (!queueCmd.manual)
            {
                connectionStr = "SqlConnectionStr";
                int freeSpaceCount = oper.getGarageFreeSpace(connectionStr,queueCmd.garageID);
                if (isParking)
                {
                    oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 0);
                    if (parkingSpaceUpdated)
                    {
                        freeSpaceCount = freeSpaceCount + 1;
                        oper.UpdateGarageFreeSpace(connectionStr,freeSpaceCount, queueCmd.garageID);
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                    }
                }
                else
                {                   
                    oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 1);
                    if (parkingSpaceUpdated)
                    {
                        freeSpaceCount = freeSpaceCount - 1;
                        oper.UpdateGarageFreeSpace(connectionStr,freeSpaceCount, queueCmd.garageID);
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 1);
                    }
                }
            }
            else
            {
                connectionStr = "SqlConnectionLocation";
                if (isParking)
                {
                    oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 0);
                    if (parkingSpaceUpdated)
                    {
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                    }
                }
                else
                {
                    oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 1);
                    if (parkingSpaceUpdated)
                    {
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 1);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 停车命令处理类
    /// </summary>
    public class StopCmd : AbstractCmd
    {
        /// <summary>
        /// 命令中号牌与对应号牌机中当前号牌比对，确认车辆
        /// </summary>
        private bool NumValidation(Command queueCmd, int countdown, float ratio)
        {
            List<NumberMachineNode> numList = ((NumberMachineMessage)NumMachine.GetMessage()).data;
            bool result = false;
            Task numberCheck = Task.Factory.StartNew(() =>
            {
                int myCountdown = countdown, count = 0;
                while (myCountdown-- > 0)
                {
                    foreach (NumberMachineNode node in numList)
                    {
                        if (queueCmd.ip.Equals(node.ip) && queueCmd.LicenseNum.Equals(node.LicenseNum))
                        {
                            count += 1;
                        }
                    }
                    Thread.Sleep(500);
                }
                if (count >= (int)(countdown * ratio))
                {
                    result = true;
                }
                else
                {
                    result = false;
                }
            });
            numberCheck.Wait();
            return result;
        }
        /// <summary>
        /// 号牌复位
        /// </summary>
        private void NumReset(Command queueCmd)
        {
            NumberMachineMessage numberMachineMessage = new NumberMachineMessage();
            numberMachineMessage.aNode = new NumberMachineNode();
            numberMachineMessage.aNode.ip = "";
            numberMachineMessage.aNode.LicenseNum = queueCmd.LicenseNum;
            queuingThread.SetMessage(numberMachineMessage);
        }
        /// <summary>
        /// 车位资源
        /// </summary>
        /// <param name="queueCmd"></param>
        /// <returns></returns>
        private Parking_Space WaitForParkingSpaceResource(Command queueCmd)
        {
            string connectionStr = null;
            //中心点
            cEntrance.parkingEntX = parkingEntX;
            cEntrance.parkingEntY = parkingEntY;
            cEntrance.parkingEntZ = parkingEntZ;
            Parking_Space ppp = new Parking_Space();
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            while (!isClosing)
            {
                if (!queueCmd.manual)
                {
                    connectionStr = "SqlConnectionStr";
                    ppp = aps.MallocParkingSpace(cEntrance, connectionStr, queueCmd);//自动 
                }
                else
                {
                    connectionStr = "SqlConnectionLocation";
                    ppp = aps.MallocParkingSpace(cEntrance, connectionStr, queueCmd);//手动
                }
                if (ppp != null)
                {
                    UILogServer.ins.log(queueCmd.LicenseNum + "已分配车位");
                    break;
                }
                Thread.Sleep(200);
                mt.EndTiming();
                int activationCount = 0;
                if (mt.IsLonger(5, 1, false, out activationCount))
                {
                    if (activationCount == 1)
                    {
                        UILogServer.ins.info(queueCmd.LicenseNum + "未获得车位");
                    }
                    if (MyTimer.restart && !mt.rolledBack)
                    {
                        mt.rolledBack = true;
                        UILogServer.ins.error(queueCmd.LicenseNum + "超时未获得车位，指令退回");
                        return null;
                    }
                }
            }
            return ppp;
        }
        /// <summary>
        /// 等待激光数据
        /// </summary>
        /// <param name="queueCmd">传入的命令</param>
        /// <param name="disappeared">车辆是否已驶离</param>
        /// <returns></returns>
        private Data WaitForLaserResource(Command queueCmd, bool disappeared)
        {
            //激光数据
            Data data = new Data();
            bool jumpOut = false;
            int disconnectionCount = 0;
            int laserID = queueCmd.id / 6 + 1;
            PLCMessage PLCMsg = null;
            jumpOut = false;
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            while (!isClosing)
            {
                PLCMsg = (PLCMessage)PLC.GetMessage();
                if (PLCMsg != null)
                {
                    foreach (LaserMessage lm in PLCMsg.laserMsgList)
                    {
                        if (lm.id == laserID && lm.data != null)
                        {
                            lock (lm)
                            {
                                //判断车辆检测结果,
                                if (disappeared)
                                {
                                    lm.abort_rescan = true;
                                    jumpOut = true;
                                    break;
                                }
                                //存储相应激光数据
                                if (lm.recorded && lm.licenseNum == queueCmd.LicenseNum)
                                {
                                    data.angleA = lm.data.angleA;
                                    data.centerX = lm.data.centerX;
                                    data.centerY = lm.data.centerY;
                                    data.length = lm.data.length;
                                    data.width = lm.data.width;
                                    data.height = lm.data.height;
                                    jumpOut = true;
                                    lm.recorded = false;
                                    lm.occupied = false;
                                    lm.licenseNum = "";
                                    break;
                                }
                                else if (lm.status == -1)
                                {
                                    disconnectionCount += 1;
                                    if (disconnectionCount == 1)
                                    {
                                        LogFile logFile = LogFile.ERROR;
                                        UILogServer.ins.error("激光" + lm.id + "连接异常");
                                        Log.WriteLog(logFile, "激光异常");
                                    }
                                    Thread.Sleep(10000);
                                }
                            }
                        }
                    }
                    if (jumpOut)
                    {
                        UILogServer.ins.log(queueCmd.LicenseNum + "激光数据已获得");
                        break;
                    }
                }
                Thread.Sleep(1000);
                mt.EndTiming();
                int activationCount = 0;
                if (mt.IsLonger(30, 1, false, out activationCount))
                {
                    if (activationCount == 1)
                    {
                        UILogServer.ins.info(queueCmd.LicenseNum + "未获取激光数据，继续等待");
                    }
                    if (MyTimer.restart && !mt.rolledBack)
                    {
                        mt.rolledBack = true;
                        UILogServer.ins.error(queueCmd.LicenseNum + "超时未获取激光数据，指令退回");
                        return null;
                    }

                }
            }
            return data;
        }
        /// <summary>
        /// 停车完成
        /// </summary>
        private bool WaitForStoreCompletionSignal(Command queueCmd, ref int parkingSpaceID, ref bool robotError, int status)
        {
            string connectionStr = null;
            PLCMessage PLCMsg = null;
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            while (!isClosing)
            {
                Thread.Sleep(1000);
                PLCMsg = (PLCMessage)PLC.GetMessage();
                int storeStatus = Convert.ToInt32(PLCMsg.originalPlcList[park_completed_address].Value);
                //停车完成信号
                if (storeStatus == status)
                {
                    UILogServer.ins.log(queueCmd.LicenseNum + "已获得停车完成信号" + status);
                    break;
                }
                else if (1 == 2)//机械手异常，则退指令，写数据库归位，判断条件需之后补充
                {
                    robotError = true;
                    queueCmd.returnedCount += 1;
                    queuingThread.SetMessage(queueCmd);
                    if (!queueCmd.manual)
                    {
                        connectionStr = "SqlConnectionStr";
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                    }
                    else
                    {
                        connectionStr = "SqlConnectionLocation";
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                    }
                    break;
                }
                mt.EndTiming();
                int activationCount = 0;
                if (mt.IsLonger(120, 1, false, out activationCount))
                {
                    if (activationCount == 1)
                    {
                        UILogServer.ins.info(queueCmd.LicenseNum + "未获得停车完成信号" + status + "，继续等待");
                    }
                    if (MyTimer.restart && !mt.rolledBack)
                    {
                        mt.rolledBack = true;
                        UILogServer.ins.error(queueCmd.LicenseNum + "等待停车完成信号" + status + "超时，流程回滚");
                        return false;
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// 等待轮距信息
        /// </summary>
        /// <param name="frontWheelbase">前轮距</param>
        /// <param name="rearWheelbase">后轮距</param>
        private bool WaitWheelbase(ref int frontWheelbase, ref int rearWheelbase)
        {
            PLCMessage PLCMsg = null;
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            while (!isClosing)
            {
                PLCMsg = (PLCMessage)PLC.GetMessage();
                int wheelbaseStatus = Convert.ToInt32(PLCMsg.originalPlcList[wheelbase_status_address].Value);
                //停车完成信号
                if (wheelbaseStatus == 3)
                {
                    frontWheelbase = Convert.ToInt32(PLCMsg.originalPlcList[frontWheelbase_address].Value);
                    rearWheelbase = Convert.ToInt32(PLCMsg.originalPlcList[rearWheelbase_address].Value);
                    UILogServer.ins.log("轮距雷达完成状态已获取");
                    break;
                }
                Thread.Sleep(1000);
                mt.EndTiming();
                int activationCount = 0;
                if (mt.IsLonger(60, 1, false, out activationCount))
                {
                    if (activationCount == 1)
                    {
                        UILogServer.ins.info("未获取轮距雷达完成状态，继续等待");
                    }
                    if (MyTimer.restart && !mt.rolledBack)
                    {
                        mt.rolledBack = true;
                        UILogServer.ins.error("超时未获取轮距雷达数据，流程回滚");
                        return false;
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// 停车流程
        /// </summary>
        /// <param name="queueCmd"></param>
        public override void executeCmd(Command queueCmd)
        {
            string connectionStr = null;
            bool disappeared = false;
            bool stopChecking = false;
            bool robotError = false;
            string numberPlate = queueCmd.LicenseNum;
            int userID = 0;

            //第一步，激光与车位：
            int status = 1;//停车
            ControlMessage cm = new ControlMessage();
            cm.status = status;
            //根据号牌机id启动对应激光
            cm.laserID = queueCmd.id / 6 + 1;
            cm.LicenseNum = queueCmd.LicenseNum;
            PLC.SetMessage(cm);
            Log.WriteLog("停车流程，车牌号为" + queueCmd.LicenseNum + "的车辆准备开启激光");
            UILogServer.ins.info("停车流程，车牌号为" + queueCmd.LicenseNum + "的车辆准备开启激光");

            //获取车位资源
            Parking_Space ppp = new Parking_Space();
            ppp = WaitForParkingSpaceResource(queueCmd);

            //过期号牌判断
            if (queueCmd.userID != "")
            {
                userID = Convert.ToInt32(queueCmd.userID);
            }
            int garageID = queueCmd.garageID;
            string realParkTime = queueCmd.TimeRecord;
            //定义号牌验证与机械手异常标志
            //Task checkNum = Task.Factory.StartNew(() =>
            //{
            //    DateTime startTime = DateTime.Now;
            //    DateTime endTime = DateTime.Now;
            //    TimeSpan t = startTime - endTime;
            //    while (!stopChecking && t.TotalSeconds <= 600)
            //    {
            //        //号牌验证,异常则退回队列
            //        Func<Command, int, float, bool> numValidationResult = new Func<Command, int, float, bool>(NumValidation);
            //        IAsyncResult result = numValidationResult.BeginInvoke(queueCmd, 10, 0.7f, null, null);
            //        bool checkResult = numValidationResult.EndInvoke(result);
            //        if (stopChecking)
            //        {
            //            return;
            //        }
            //        if (!checkResult)
            //        {
            //            UILogServer.ins.info("停车命令" + queueCmd.LicenseNum + " 与当前车辆不一致");
            //            disappeared = true;
            //            return;
            //            //未能停车，将车辆状态复位
            //            //oper.UpdateVehicleParkState(queueCmd.LicenseNum, 0);
            //        }
            //        endTime = DateTime.Now;
            //        t = startTime - endTime;
            //    }
            //});

            Data dataReal = new Data();
            dataReal = WaitForLaserResource(queueCmd, disappeared);

            //判断车位与激光资源有效性,无效则回滚
            if (ppp == null || dataReal == null)
            {
                Rollback(queueCmd, ppp.parkingSpaceID, false, true);
                return;
            }
            //车位赋值与写数据库
            int parkingSpaceID = ppp.parkingSpaceID;
            int parkingSpaceX = ppp.parkingSpaceX;
            int parkingSpaceY = ppp.parkingSpaceY;
            int parkingSpaceZ = ppp.parkingSpaceZ;
            if (!queueCmd.manual)
            {
                connectionStr = "SqlConnectionStr";
                //更新云端车位表车位状态
                oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 1);
                //更新车库表剩余车位数
                int freeSpaceCount = oper.getGarageFreeSpace(connectionStr, garageID);
                freeSpaceCount = freeSpaceCount - 1;
                oper.UpdateGarageFreeSpace(connectionStr, freeSpaceCount, garageID);
            }
            else
            {
                connectionStr = "SqlConnectionLocation";
                //更新本地车位表车位状态
                oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 1);
                //更新车库表剩余车位数
                int freeSpaceCount = oper.getGarageFreeSpace(connectionStr,garageID);
                freeSpaceCount = freeSpaceCount - 1;
                oper.UpdateGarageFreeSpace(connectionStr,freeSpaceCount, garageID);
            }
            //号牌失效，数据库回滚
            if (disappeared)
            {
                NumReset(queueCmd);
                if (!queueCmd.manual)
                {
                    connectionStr = "SqlConnectionStr";
                    oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 0);
                }
                else
                {
                    connectionStr = "SqlConnectionLocation";
                    oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 0);
                }
                return;
            }
            //开始启动机械手，停止检测号牌
            stopChecking = true;
            UILogServer.ins.log(queueCmd.LicenseNum + "停止号牌核对，准备启动机械手");
            int robotID = 0;
            robotID = queueCmd.id / 6 + 1;
            int frontWheelbase = 0;
            int rearWheelbase = 0;
            //需要先遍历robot数组，根据id找到对应机械手

            if (!WaitForRobotResource(robotID))
            {
                Rollback(queueCmd, parkingSpaceID, true, true);
                return;
            }


            //第二步，机械手：
            status = 2;
            cm.status = status;
            cm.RobotID = robotID;//启动对应机械手
                                 //激光数据
            cm.centerX = Convert.ToString(dataReal.centerX);
            cm.centerY = Convert.ToString(dataReal.centerY);
            cm.angleA = Convert.ToString(dataReal.angleA);
            cm.length = Convert.ToString(dataReal.length);
            cm.width = Convert.ToString(dataReal.width);
            cm.height = Convert.ToString(dataReal.height);
            cm.parkingSpaceID = Convert.ToString(parkingSpaceID);
            cm.parkingSpaceX = Convert.ToString(parkingSpaceX);
            cm.parkingSpaceY = Convert.ToString(parkingSpaceY);
            cm.parkingSpaceZ = Convert.ToString(parkingSpaceZ);
            PLC.SetMessage(cm);
            Log.WriteLog("停车流程，抓车:" + queueCmd.LicenseNum);
            UILogServer.ins.info("停车流程，抓车:" + queueCmd.LicenseNum);

            if (!WaitWheelbase(ref frontWheelbase, ref rearWheelbase))
            {
                Rollback(queueCmd, parkingSpaceID, true, true);
                return;
            }
            if (!WaitForStoreCompletionSignal(queueCmd, ref parkingSpaceID, ref robotError, 1))
            {
                Rollback(queueCmd, parkingSpaceID, true, true);
                return;
            }

            //第三步，停车完成：
            status = 3;
            cm.status = status;
            PLC.SetMessage(cm);
            //机械手异常则回滚
            if (!WaitForStoreCompletionSignal(queueCmd, ref parkingSpaceID, ref robotError, 0))
            {
                Rollback(queueCmd, parkingSpaceID, true, true);
                return;
            }

            //停车流程结束，将相应车牌复位
            NumReset(queueCmd);
            Log.WriteLog("停车完成，状态复位");
            UILogServer.ins.info(queueCmd.LicenseNum + "停车完成，状态复位");
            Robot.robot1.occupied = false;
            //自动化测试用
            ManualParkingSimul.ins.Update(Int32.Parse(queueCmd.LicenseNum.Substring(2, 1)));
            //根据号牌查找车型
            //int vehicleTypeID = oper.getVehicleTypeID(numberPlate);
            //判断测量数据是否准确
            //bool isDataRight = oper.IsDataRight(vehicleTypeLength, vehicleTypeWidth, vehicleTypeHeight, vehicleTypeWheelbase, vehicleTypeID);

            //正常写入数据库
            if (userID != 0)
            {
                if (!queueCmd.manual)
                {
                    connectionStr = "SqlConnectionStr";
                    //更新云端数据库
                    //插入停车记录表
                    int parkingRecordsID = oper.InsertToParkingRecords(connectionStr,userID, numberPlate, parkingSpaceID, garageID, 3, realParkTime);
                    //车辆表更新车辆信息
                    oper.UpdateVehicle(connectionStr,numberPlate, 1, realParkTime, parkingRecordsID, parkingSpaceID, 1, frontWheelbase, rearWheelbase);
                    //插入消息队列表
                    oper.InsertToMessageQueue(connectionStr,userID, "停车成功", 1);
                }
                else
                {
                    connectionStr = "SqlConnectionLocation";
                    //插入停车记录表
                    int parkingRecordsID = oper.InsertToLocalParkingRecords(connectionStr,1, userID, numberPlate, parkingSpaceID, garageID, 3, realParkTime, frontWheelbase, rearWheelbase);
                }
            }
            //异常写入日志文件
            else
            {
                LogFile logFile = LogFile.ERROR_NUMBERPLATE;
                Log.WriteLog(logFile, "号牌：" + numberPlate);
                Log.WriteLog(logFile, "入库时间：" + realParkTime);
                Log.WriteLog(logFile, "车位id：" + parkingSpaceID);
                Log.WriteLog(logFile, "车位x：" + parkingSpaceX);
                Log.WriteLog(logFile, "车位y：" + parkingSpaceY);
                Log.WriteLog(logFile, "车位z：" + parkingSpaceZ);
                //异常情况处理有待讨论
            }
        }
    }

    /// <summary>
    /// 取车命令处理类
    /// </summary>
    public class FetchCmd : AbstractCmd
    {
        private bool waitForFetchCompletionSignal(Command queueCmd, ref int parkingSpaceID, ref bool robotError, int status)
        {
            string connectionStr = null;
            PLCMessage PLCMsg = null;
            MyTimer mt = new MyTimer();
            mt.StartTiming();
            while (!isClosing)
            {
                Thread.Sleep(2000);
                PLCMsg = (PLCMessage)PLC.GetMessage();
                int fetchingStatus = Convert.ToInt32(PLCMsg.originalPlcList[fetch_completed_address].Value);
                //取车完成信号
                if (fetchingStatus == status)
                {
                    //取车完成后或可归零
                    UILogServer.ins.log(queueCmd.LicenseNum + "获得取车完成信号" + status);
                    break;
                }
                else if (1 == 2)//机械手异常，则退指令，写数据库归位，判断条件需之后补充
                {
                    robotError = true;
                    queueCmd.returnedCount += 1;
                    queuingThread.SetMessage(queueCmd);
                    if (!queueCmd.manual)
                    {
                        connectionStr = "SqlConnectionStr";
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                    }
                    else
                    {
                        connectionStr = "SqlConnectionLocation";
                        oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                    }
                    break;
                }
                mt.EndTiming();
                int activationCount = 0;
                if (mt.IsLonger(120, 1, false, out activationCount))
                {
                    if (activationCount == 1)
                    {
                        UILogServer.ins.info(queueCmd.LicenseNum + "未获得取车完成信号" + status + "，继续等待");
                    }
                    if (MyTimer.restart && !mt.rolledBack)
                    {
                        mt.rolledBack = true;
                        UILogServer.ins.error(queueCmd.LicenseNum + "等待取车完成信号" + status + "超时，流程回滚");
                        return false;
                    }
                }
            }
            return true;
        }

        public override void executeCmd(Command queueCmd)
        {
            string connectionStr = null;
            PLCMessage PLCMsg = null;
            Vehicle vehiclelist = null;
            if (queueCmd.manual)
            {
                connectionStr = "SqlConnectionLocation";
                vehiclelist = oper.GetLocalVehicle(connectionStr,queueCmd.LicenseNum, queueCmd.garageID);
            }
            else
            {             
                connectionStr = "SqlConnectionStr";
                vehiclelist = oper.GetVehicle(connectionStr,queueCmd.LicenseNum);
            }
            int parkingSpaceID = vehiclelist.parkingSpaceID;
            int garageID = vehiclelist.garageID;
            int frontwheelbase = vehiclelist.frontwheelbase;
            int rearwheelbase = vehiclelist.rearwheelbase;
            bool robotError = false;
            Fetching_Space fslist = null;
            if (queueCmd.manual)
            {
                connectionStr = "SqlConnectionLocation";
                fslist = oper.GetFetchingSpace(connectionStr,parkingSpaceID);
            }
            else
            {
                connectionStr = "SqlConnectionStr";
                fslist = oper.GetFetchingSpace(connectionStr,parkingSpaceID);
            }
            int parkingSpaceX = fslist.parkingSpaceX;
            int parkingSpaceY = fslist.parkingSpaceY;
            int parkingSpaceZ = fslist.parkingSpaceZ;
            ControlMessage cm = new ControlMessage();

            int robotID = 0;
            robotID = parkingSpaceID / 15 + 1;
            if (!WaitForRobotResource(robotID))
            {
                Rollback(queueCmd, parkingSpaceID, true, false);
                return;
            }

            //取车
            int status = 4;
            cm.status = status;
            //先手动赋值
            cm.RobotID = 1;
            cm.fetchPosition = 1;//放置地址
            cm.parkingSpaceID = Convert.ToString(parkingSpaceID);
            cm.parkingSpaceX = Convert.ToString(parkingSpaceX);
            cm.parkingSpaceY = Convert.ToString(parkingSpaceY);
            cm.parkingSpaceZ = Convert.ToString(parkingSpaceZ);
            cm.frontWheelbase = frontwheelbase;
            cm.rearWheelbase = rearwheelbase;
            PLC.SetMessage(cm);

            Console.WriteLine("取车:" + queueCmd.LicenseNum);
            Log.WriteLog("取车:" + queueCmd.LicenseNum);
            UILogServer.ins.info("取车:" + queueCmd.LicenseNum);
            //等待PLC取车完成信号
            if (!waitForFetchCompletionSignal(queueCmd, ref parkingSpaceID, ref robotError, 1))
            {
                Rollback(queueCmd, parkingSpaceID, true, false);
                return;
            }
            //取车完成
            status = 5;
            ControlMessage cm2 = new ControlMessage();
            cm2.status = status;
            //先手动赋值
            cm2.RobotID = 1;
            PLC.SetMessage(cm2);
            if (!waitForFetchCompletionSignal(queueCmd, ref parkingSpaceID, ref robotError, 0))
            {
                Rollback(queueCmd, parkingSpaceID, true, false);
                return;
            }
            Robot.robot1.occupied = false;
            Log.WriteLog("号牌：" + queueCmd.LicenseNum + "取车完成");
            UILogServer.ins.info("号牌：" + queueCmd.LicenseNum + "取车完成");
            //自动化测试用
            ManualParkingSimul.ins.Update(Int32.Parse(queueCmd.LicenseNum.Substring(2,1)));

            //数据库更新
            if (!queueCmd.manual)
            {
                connectionStr = "SqlConnectionStr";
                //云端数据库更新
                //更新车库表车位数
                int freeSpaceCount = oper.getGarageFreeSpace(connectionStr,garageID);
                freeSpaceCount = freeSpaceCount + 1;
                oper.UpdateGarageFreeSpace(connectionStr,freeSpaceCount, garageID);
                //更新车位表车位状态
                oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                //更新车辆表车辆停车状态
                oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 0);
                //更新停车记录表
                oper.UpdateParkingRecords(connectionStr,6, queueCmd.TimeRecord, queueCmd.parkingRecordsID);

                ////本地数据库更新
                //locationOper.UpdateGarageFreeSpace(freeSpaceCount, garageID);
                ////更新车位表车位状态
                //locationOper.UpdateParkingSpaceState(parkingSpaceID, 0);
                ////更新车辆表车辆停车状态
                //locationOper.UpdateVehicleParkState(queueCmd.LicenseNum, 0);
                ////更新停车记录表
                //locationOper.UpdateParkingRecords(0, 6, queueCmd.TimeRecord, queueCmd.parkingRecordsID);
            }
            else
            {
                connectionStr = "SqlConnectionLocation";
                //更新车库表车位数
                int freeSpaceCount = oper.getGarageFreeSpace(connectionStr,garageID);
                freeSpaceCount = freeSpaceCount + 1;
                oper.UpdateGarageFreeSpace(connectionStr,freeSpaceCount, garageID);
                //更新车位表车位状态
                oper.UpdateParkingSpaceState(connectionStr,parkingSpaceID, 0);
                ////更新车辆表车辆停车状态
                //locationOper.UpdateVehicleParkState(queueCmd.LicenseNum, 0);
                //更新停车记录表
                oper.UpdateParkingRecords(connectionStr,0, 6, queueCmd.TimeRecord, queueCmd.parkingRecordsID);
            }
        }
    }

    /// <summary>
    /// 异常命令处理类
    /// </summary>
    public class ExceptionCmd : AbstractCmd
    {
        public override void executeCmd(Command queueCmd)
        {
            string connectionStr = "SqlConnectionLocation";
            if (queueCmd.commandType == 'e')
            {
                int userId = Convert.ToInt32(queueCmd.userID);
                //过期用户指令
                oper.InsertToMessageQueue(connectionStr,userId, "停车异常，请联系管理员！", 2);
                //未能停车，将车辆状态复位
                oper.UpdateVehicleParkState(connectionStr,queueCmd.LicenseNum, 0);
                LogFile logFile = LogFile.ERROR_NUMBERPLATE;
                Log.WriteLog(logFile, "过期用户指令,车牌号：" + queueCmd.LicenseNum);
                UILogServer.ins.error("过期用户指令,车牌号：" + queueCmd.LicenseNum);
                //continue;
            }
        }
    }

    /// <summary>
    /// 简单命令工厂
    /// </summary>
    public class SimpleCMDFactory
    {
        public AbstractCmd createCmd(Command queueCmd)
        {
            AbstractCmd abstractCmd = null;

            if (queueCmd.commandType == 's')
            {
                abstractCmd = new StopCmd();
            }
            if (queueCmd.commandType == 'f')
            {
                abstractCmd = new FetchCmd();
            }
            if (queueCmd.commandType == 'e')
            {
                abstractCmd = new ExceptionCmd();
            }
            return abstractCmd;
        }
    }

}
